#import "winiphone.h"

#include <stdio.h>
#include "hack.h"
#include "dlb.h"

#undef DEFAULT_WINDOW_SYS
#define DEFAULT_WINDOW_SYS "iphone"

#pragma mark Provided by UI

extern int getCharacter();
extern const char *getAbsolutePath(const char *filename);

extern void putString(winid wid, int attr, const char *text);
extern void printGlyph(int x, int y, int glyph);
extern void rawPrint(const char *text);
extern char ynFunction(const char *question, const char *choices, int defaultChoice);

extern int createWindow(int windowType);
extern void clearWindow(int windowId);
extern void displayWindow(int windowId);
extern void destroyWindow(int windowId);

extern void delayOutput();

extern void startMenu();
extern void addMenuItem(int glyph, const char *item);
extern void endMenu(const char *prompt);

extern int clipX;
extern int clipY;

#pragma mark Auxiliary

void intron() {}
void introff() {}

void error(const char *s, ...) {
	printf("error: %s", s);
	// If we exit with non-zero status, Xcode gets mad at the Simulator.
	exit(0);
}

//! Is this acceptable?
void regularize(char *s) {}

//! Is this acceptable?
int child(int wt) {
	return 0;
}

void process_options(int argc, char *argv[]) {}

FILE *iphone_fopen(const char *filename, const char *mode) {
	const char *path = getAbsolutePath(filename);
	FILE *file = fopen(path, mode);
	return file;
}

#pragma mark Window API Functions

void iphone_init_nhwindows(int* argc, char** argv);
void iphone_player_selection();
void iphone_askname();
void iphone_get_nh_event();
void iphone_exit_nhwindows(const char *str);
void iphone_suspend_nhwindows(const char *str);
void iphone_resume_nhwindows();
winid iphone_create_nhwindow(int type);
void iphone_clear_nhwindow(winid wid);
void iphone_display_nhwindow(winid wid, BOOLEAN_P block);
void iphone_destroy_nhwindow(winid wid);
void iphone_curs(winid wid, int x, int y);
void iphone_putstr(winid wid, int attr, const char *text);
void iphone_display_file(const char *filename, BOOLEAN_P must_exist);
void iphone_start_menu(winid wid);
void iphone_add_menu(winid wid, int glyph, const ANY_P *identifier,
		CHAR_P accelerator, CHAR_P group_accel, int attr, 
		const char *str, BOOLEAN_P presel);
void iphone_end_menu(winid wid, const char *prompt);
int iphone_select_menu(winid wid, int how, menu_item **menu_list);
void iphone_update_inventory();
void iphone_mark_synch();
void iphone_wait_synch();
void iphone_cliparound(int x, int y);
void iphone_cliparound_window(winid wid, int x, int y);
void iphone_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph);
void iphone_raw_print(const char *str);
void iphone_raw_print_bold(const char *str);
int iphone_nhgetch();
int iphone_nh_poskey(int *x, int *y, int *mod);
void iphone_nhbell();
int iphone_doprev_message();
char iphone_yn_function(const char *question, const char *choices, CHAR_P def);
void iphone_getlin(const char *prompt, char *line);
int iphone_get_ext_cmd();
void iphone_number_pad(int num);
void iphone_delay_output();
void iphone_start_screen();
void iphone_end_screen();
void iphone_outrip(winid wid, int how);

#pragma mark Window Structure

struct window_procs iphone_procs = {
	"iphone",
	WC_COLOR|WC_HILITE_PET|
	WC_ASCII_MAP|WC_TILED_MAP|
	WC_FONT_MAP|WC_TILE_FILE|WC_TILE_WIDTH|WC_TILE_HEIGHT|
	WC_PLAYER_SELECTION|WC_SPLASH_SCREEN,
	0L,
	iphone_init_nhwindows,
	iphone_player_selection,
	iphone_askname,
	iphone_get_nh_event,
	iphone_exit_nhwindows,
	iphone_suspend_nhwindows,
	iphone_resume_nhwindows,
	iphone_create_nhwindow,
	iphone_clear_nhwindow,
	iphone_display_nhwindow,
	iphone_destroy_nhwindow,
	iphone_curs,
	iphone_putstr,
	iphone_display_file,
	iphone_start_menu,
	iphone_add_menu,
	iphone_end_menu,
	iphone_select_menu,
	genl_message_menu,	  /* no need for X-specific handling */
	iphone_update_inventory,
	iphone_mark_synch,
	iphone_wait_synch,
#ifdef CLIPPING
	iphone_cliparound,
#endif
#ifdef POSITIONBAR
	donull,
#endif
	iphone_print_glyph,
	iphone_raw_print,
	iphone_raw_print_bold,
	iphone_nhgetch,
	iphone_nh_poskey,
	iphone_nhbell,
	iphone_doprev_message,
	iphone_yn_function,
	iphone_getlin,
	iphone_get_ext_cmd,
	iphone_number_pad,
	iphone_delay_output,
#ifdef CHANGE_COLOR	 /* only a Mac option currently */
	donull,
	donull,
#endif
	/* other defs that really should go away (they're tty specific) */
	iphone_start_screen,
	iphone_end_screen,
	iphone_outrip,
	genl_preference_update,
};

#pragma mark API Implementation

void iphone_init_nhwindows(int* argc, char** argv) {}

void iphone_player_selection() {
	//! how will we select the player?
	//printf("player_selection\n");
}

void iphone_askname() {
	//! how will we ask for the name?
	//printf("askname\n");
	strncpy(plname, "Hero", sizeof(plname));
}

void iphone_get_nh_event() {}

void iphone_exit_nhwindows(const char *str) {
	//! Means that it's time to exit the app.
	printf("exit_nhwindows\n");
}

void iphone_suspend_nhwindows(const char *str) {}

void iphone_resume_nhwindows() {}

winid iphone_create_nhwindow(int type) {
	return createWindow(type);
}

void iphone_clear_nhwindow(winid wid) {
	clearWindow(wid);
}

void iphone_display_nhwindow(winid wid, BOOLEAN_P block) {
	//! might use the block flag to determine how the corresponding view will work
	//printf("block? %d\n", block);
	displayWindow(wid);
}

void iphone_destroy_nhwindow(winid wid) {
	destroyWindow(wid);
}

void iphone_curs(winid wid, int x, int y) {
	//! used for identification and teleport
}

void iphone_putstr(winid wid, int attr, const char *text) {
	putString(wid, attr, text);
}

void iphone_display_file(const char *filename, BOOLEAN_P must_exist) {
	//! what do you want to show here?
	printf("display_file: %s\n", filename);
}

void iphone_start_menu(winid wid) {
	startMenu();
}

void iphone_add_menu(winid wid, int glyph, const ANY_P *identifier,
		CHAR_P accelerator, CHAR_P group_accel, int attr, 
		const char *str, BOOLEAN_P presel) {
	//! might need to use the identifier?
	//! Likewise, might need to use `presel`
	//printf("add_menu: %s\n", str);
	addMenuItem(glyph, str);
}

void iphone_end_menu(winid wid, const char *prompt) {
	endMenu(prompt);
}

int iphone_select_menu(winid wid, int how, menu_item **menu_list) {
	//!! will deal with this later: it's tricky.
	printf("select_menu\n");
	return 0;
}

void iphone_update_inventory() {
	//! called when your inventory changes -- don't need to do anything for this yet
	//printf("update_inventory\n");
}

void iphone_mark_synch() {}
void iphone_wait_synch() {}

void iphone_cliparound(int x, int y) {
	clipX = x;
	clipY = y;
}

void iphone_cliparound_window(winid wid, int x, int y) {}

void iphone_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph) {
	printGlyph(x, y, glyph);
}

void iphone_raw_print(const char *str) {
	rawPrint(str);
}

void iphone_raw_print_bold(const char *str) {
	rawPrint(str);
}

int iphone_nhgetch() {
	return getCharacter();
}

int iphone_nh_poskey(int *x, int *y, int *mod) {
	return getCharacter();
}

void iphone_nhbell() {}
int iphone_doprev_message() { return 0; }

char iphone_yn_function(const char *question, const char *choices, CHAR_P def) {
	return ynFunction(question, choices, def);
}

void iphone_getlin(const char *prompt, char *line) {
	//! trigger with shift+E
	printf("getlin: %s\n", prompt);
	strncpy(line, "elbereth", BUFSZ);
}

int iphone_get_ext_cmd() {
	//! invoked when you use '#'
	// An index into extcmdlist[] is returned on a successful selection, -1 otherwise.
	printf("get_ext_cmd\n");
	return -1;
}

void iphone_number_pad(int num) {}

void iphone_delay_output() {
	delayOutput();
}

void iphone_start_screen() {}
void iphone_end_screen() {}

void iphone_outrip(winid wid, int how) {
	//! not sure when this is called
	printf("outrip\n");
}

#pragma mark Main NetHack.

void mainNetHack() {
	int argc = 0;
	char **argv = NULL;

	choose_windows(DEFAULT_WINDOW_SYS);

	initoptions();
	init_nhwindows(&argc, argv);
	
	process_options(argc, argv);

	//! Might call `askname();` at this point.
	
	dlb_init();
	
	//! They set `x_maze_max` and `y_maze_max`.
	
	vision_init();
	
	display_gamewindows();
	
	//! save game unhandled
	#define SAVE_FILE_IS_PRESENT 0
	if (SAVE_FILE_IS_PRESENT) {
		//! restore saved game
	} else {
		player_selection();
		newgame();
		
		flags.move = 0;
		set_wear();
		(void) pickup(1);
	}

	moveloop();
}